﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Xml;
using DiscoveryLogic.Common.Utilities;
using System.Windows.Media;

namespace DiscoveryLogic.Analytics.DataObjects.Visuals
{
    public class NetworkVisual
    {
        #region props
        private string _NetworkName;
        /// <summary></summary>
        public string NetworkName
        {
            get
            {
                return this._NetworkName;
            }
            set
            {
                this._NetworkName = value;
            }
        }

        private Dictionary<EntityType,VerticeVisual> _EntityVisuals;
        /// <summary></summary>
        public Dictionary<EntityType,VerticeVisual> EntityVisuals
        {
            get
            {
                return this._EntityVisuals;
            }
            set
            {
                this._EntityVisuals = value;
            }
        }

        private Dictionary<EntityType,Dictionary<EntityType,EdgeVisual>> _EdgeVisuals;
        /// <summary></summary>
        public Dictionary<EntityType, Dictionary<EntityType, EdgeVisual>> EdgeVisuals
        {
            get
            {
                return this._EdgeVisuals;
            }
            set
            {
                this._EdgeVisuals = value;
            }
        }
        #endregion

        public NetworkVisual()
        {
            this._NetworkName = string.Empty;
            this._EntityVisuals=new Dictionary<EntityType, VerticeVisual>();
            this._EdgeVisuals = new Dictionary<EntityType, Dictionary<EntityType, EdgeVisual>>();
        }

        public static NetworkVisual Read(string networkName)
        {
            NetworkVisual netV = new NetworkVisual();
            string appFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
            appFolderPath = Path.Combine(appFolderPath, "Network Data");
            if (!Directory.Exists(appFolderPath))
                Directory.CreateDirectory(appFolderPath);
            string filePath = Path.Combine(appFolderPath, networkName + ".viz");
            if (!File.Exists(filePath))
            {
                netV = Default;
                netV.NetworkName = networkName;
                return netV;
            }
            XmlDocument xDoc=new XmlDocument();
            xDoc.Load(filePath);
            
            XmlNode root=xDoc.DocumentElement;
            netV.NetworkName = XmlDataUtil.GetAttributeValue(root, "NetworkName", "");
            netV.EntityVisuals=new Dictionary<EntityType, VerticeVisual>();
            XmlNodeList vNodes = root.SelectNodes("VerticeVisuals/VerticeVisual");
            if (vNodes != null && vNodes.Count > 0)
            {
                foreach (XmlNode vNode in vNodes)
                {
                    VerticeVisual vv = new VerticeVisual();
                    vv.EntityType =
                        (EntityType)
                        Enum.Parse(typeof (EntityType),
                                   XmlDataUtil.GetAttributeValue(vNode, "EntityType", EntityType.Grants.ToString()));
                    double w = double.Parse(XmlDataUtil.GetAttributeValue(vNode, "SizeW", "40"));
                    double h = double.Parse(XmlDataUtil.GetAttributeValue(vNode, "SizeH", "40"));
                    vv.Size=new Size(w,h);
                    vv.Icon = XmlDataUtil.GetAttributeValue(vNode, "Icon", "");
                    vv.Color = ColorUtil.ParseMediaColor(XmlDataUtil.GetAttributeValue(vNode, "Color", 
                        ColorUtil.ToString(Colors.Blue)));
                    vv.Shape =
                        (VerticeShape)
                        Enum.Parse(typeof (VerticeShape),
                                   XmlDataUtil.GetAttributeValue(vNode, "Shape", VerticeShape.Custom.ToString()));
                    vv.SizeMeasure =
                        (DynamicVerticeSizeMeasure)
                        Enum.Parse(typeof (DynamicVerticeSizeMeasure),
                                   XmlDataUtil.GetAttributeValue(vNode, "SizeMeasure",
                                                                 DynamicVerticeSizeMeasure.Degree.ToString()));
                    vv.SelectedColor = ColorUtil.ParseMediaColor(XmlDataUtil.GetAttributeValue(vNode, "SelectedColor", 
                        ColorUtil.ToString(Colors.Yellow)));
                    vv.SelectedIcon = XmlDataUtil.GetAttributeValue(vNode, "SelectedIcon", "");
                    vv.ShowLabelAll = bool.Parse(XmlDataUtil.GetAttributeValue(vNode, "ShowLabelAll", false.ToString()));
                    vv.ShowLabelsWhenDegreeAbove =
                        int.Parse(XmlDataUtil.GetAttributeValue(vNode, "ShowLabelWhenDegreeAbove", "0"));
                    vv.LabelColor = ColorUtil.ParseMediaColor(XmlDataUtil.GetAttributeValue(vNode, "LabelColor", 
                        ColorUtil.ToString(Colors.White)));
                    vv.ShowLabelsForNames=new List<string>();
                    XmlNodeList showLabelForNameNodes = vNode.SelectNodes("ShowLabelForNames/ShowLabelForName");
                    if(showLabelForNameNodes !=null && showLabelForNameNodes.Count>0)
                    {
                        foreach(XmlNode showLabelForNameNode in showLabelForNameNodes)
                        {
                            string name = XmlDataUtil.GetAttributeValue(showLabelForNameNode, "Name", "");
                            vv.ShowLabelsForNames.Add(name);
                        }
                    }
                    vv.FlagColors=new Dictionary<string, Color>();
                    XmlNodeList flagNodes = vNode.SelectNodes("Flags/Flag");
                    if(flagNodes !=null && flagNodes.Count>0)
                    {
                        foreach(XmlNode flagNode in flagNodes)
                        {
                            string flag = XmlDataUtil.GetAttributeValue(flagNode, "Flag", "0");
                            Color flagColor = ColorUtil.ParseMediaColor(
                                XmlDataUtil.GetAttributeValue(
                                    flagNode, "Color",
                                    ColorUtil.ToString(Colors.White)));
                            vv.FlagColors.Add(flag, flagColor);
                        }
                    }

                    netV.EntityVisuals.Add(vv.EntityType,vv);
                }
            }

            netV.EdgeVisuals=new Dictionary<EntityType, Dictionary<EntityType, EdgeVisual>>();
            XmlNodeList eNodes = root.SelectNodes("EdgeVisuals/EdgeVisual");
            foreach(XmlNode eNode in eNodes)
            {
                EntityType fromEntity =
                    (EntityType)
                    Enum.Parse(
                        typeof (EntityType),
                        XmlDataUtil.GetAttributeValue(
                            eNode, "FromEntity", EntityType.Grants.ToString()));
                EntityType toEntity =
                    (EntityType)
                    Enum.Parse(
                        typeof (EntityType),
                        XmlDataUtil.GetAttributeValue(
                            eNode, "ToEntity", EntityType.Grants.ToString()));
                EdgeVisual ev=new EdgeVisual();
                ev.FromEntity = fromEntity;
                ev.ToEntity = toEntity;
                ev.Color = ColorUtil.ParseMediaColor(XmlDataUtil.GetAttributeValue(eNode, "Color", ""));
                ev.LineStyle =
                    (EdgeLineStyle)
                    Enum.Parse(typeof (EdgeLineStyle),
                               XmlDataUtil.GetAttributeValue(eNode, "LineStyle", EdgeLineStyle.Solid.ToString()));
                ev.Thickness = double.Parse(XmlDataUtil.GetAttributeValue(eNode, "Thickness", "2"));
                ev.ThicknessMeasure =
                    (EdgeThicknessMeasure)
                    Enum.Parse(typeof (EdgeThicknessMeasure),
                               XmlDataUtil.GetAttributeValue(eNode, "ThicknessMeasure",
                                                             EdgeThicknessMeasure.Fixed.ToString()));
                ev.ShowDistance = bool.Parse(XmlDataUtil.GetAttributeValue(eNode, "ShowDistance", false.ToString()));
                ev.DistanceScale = double.Parse(XmlDataUtil.GetAttributeValue(eNode, "DistanceScale", "2.5"));

                if (netV.EdgeVisuals.ContainsKey(fromEntity))
                {
                    Dictionary<EntityType, EdgeVisual> evs = netV.EdgeVisuals[fromEntity];
                    if(!evs.ContainsKey(toEntity))
                        evs.Add(toEntity,ev);
                    netV.EdgeVisuals[fromEntity] = evs;
                }
                else
                {
                    Dictionary<EntityType, EdgeVisual> evs=new Dictionary<EntityType, EdgeVisual>();
                    evs.Add(toEntity, ev);
                    netV.EdgeVisuals.Add(fromEntity, evs);
                }
            }
            
            return netV;
        }

        public static NetworkVisual Default
        {
            get
            {
                NetworkVisual netVisual=new NetworkVisual();
                netVisual.NetworkName = string.Empty;
                netVisual.EntityVisuals=new Dictionary<EntityType, VerticeVisual>();
                // grant 
                foreach(EntityType et in Enum.GetValues(typeof(EntityType)))
                {
                    VerticeVisual vV = new VerticeVisual();
                    vV.Size = new Size(20, 20);
                    vV.Icon = EntityIcons.GetEntityIconByType(et);
                    vV.Color = Colors.Blue;
                    vV.Shape = VerticeShape.Custom;
                    vV.EntityType = EntityType.Grants;
                    vV.SizeMeasure = DynamicVerticeSizeMeasure.Fixed;
                    vV.SelectedColor = Colors.Red;
                    vV.SelectedIcon = EntityIcons.GetSelectedEntityIconByType(et);
                    vV.ShowLabelAll = false;
                    vV.ShowLabelsForNames=new List<string>();
                    vV.ShowLabelsWhenDegreeAbove = 0;
                    vV.LabelColor = Colors.Green;
                    vV.FlagColors=new Dictionary<string, Color>();
                    
                    netVisual.EntityVisuals.Add(et, vV);
                }

                //// person
                //vV = new VerticeVisual();
                //vV.Size = new Size(20, 20);
                //vV.SizeMeasure = DynamicVerticeSizeMeasure.Fixed;
                //vV.Icon = EntityIcons.PersonIcon;
                //vV.SelectedIcon = EntityIcons.SelectedPersonIcon;
                //vV.EntityType = EntityType.Persons;
                //netVisual.EntityVisuals.Add(EntityType.Persons, vV);
                //// org
                //vV = new VerticeVisual();
                //vV.Size = new Size(20, 20);
                //vV.SizeMeasure = DynamicVerticeSizeMeasure.Fixed;
                //vV.Icon = EntityIcons.OrgIcon;
                //vV.SelectedIcon = EntityIcons.SelectedOrgIcon;
                //vV.EntityType = EntityType.Organizations;
                //netVisual.EntityVisuals.Add(EntityType.Organizations, vV);
                //// pub
                //vV = new VerticeVisual();
                //vV.Size = new Size(20, 20);
                //vV.SizeMeasure = DynamicVerticeSizeMeasure.Fixed;
                //vV.Icon = EntityIcons.PubIcon;
                //vV.SelectedIcon = EntityIcons.SelectedPubIcon;
                //vV.EntityType = EntityType.Publications;
                //netVisual.EntityVisuals.Add(EntityType.Publications, vV);
                //// doc 
                //vV = new VerticeVisual();
                //vV.Size = new Size(20, 20);
                //vV.SizeMeasure = DynamicVerticeSizeMeasure.Fixed;
                //vV.Icon = EntityIcons.DocIcon;
                //vV.SelectedIcon = EntityIcons.SelectedDocIcon;
                //vV.EntityType = EntityType.Document;
                //netVisual.EntityVisuals.Add(EntityType.Document, vV);
                //// subj
                //vV = new VerticeVisual();
                //vV.Size = new Size(20, 20);
                //vV.SizeMeasure = DynamicVerticeSizeMeasure.Fixed;
                //vV.Icon = EntityIcons.SubjIcon;
                //vV.SelectedIcon = EntityIcons.SelectedSubjIcon;
                //vV.EntityType = EntityType.Subject;
                //netVisual.EntityVisuals.Add(EntityType.Subject, vV);
                EdgeVisual eV = new EdgeVisual();
                eV.Color = Colors.White;
                eV.LineStyle = EdgeLineStyle.Solid;
                eV.Thickness = 2;
                netVisual.EdgeVisuals = new Dictionary<EntityType, Dictionary<EntityType, EdgeVisual>>();
                foreach (EntityType fromEntity in Enum.GetValues(typeof(EntityType)))
                {
                    Dictionary<EntityType, EdgeVisual> eVs = new Dictionary<EntityType, EdgeVisual>();
                    foreach (EntityType toEntity in Enum.GetValues(typeof (EntityType)))
                    {
                        EdgeVisual ev = new EdgeVisual();
                        ev.Color = Colors.White;
                        ev.FromEntity = fromEntity;
                        ev.LineStyle = EdgeLineStyle.Solid;
                        ev.Thickness = 2;
                        ev.ThicknessMeasure = EdgeThicknessMeasure.Fixed;
                        ev.ToEntity = toEntity;
                        ev.ShowDistance = false;
                        ev.DistanceScale = 2.5;
                        eVs.Add(toEntity, ev);
                    }
                    netVisual.EdgeVisuals.Add(fromEntity, eVs);
                }
                return netVisual;
            }
        }

        public void Save()
        {
            string appFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
            appFolderPath = Path.Combine(appFolderPath, "Network Data");
            if (!Directory.Exists(appFolderPath))
                Directory.CreateDirectory(appFolderPath);
            string filePath = Path.Combine(appFolderPath, this.NetworkName + ".viz");
            if(File.Exists(filePath))
                File.Delete(filePath);
            XmlDocument xDoc = new XmlDocument();
            xDoc.LoadXml("<NetworkVisual></NetworkVisual>");
            XmlNode root = xDoc.DocumentElement;
            XmlDataUtil.UpdateAttribute(ref xDoc, root, "NetworkName",this.NetworkName);
            XmlNode vNodes = XmlDataUtil.AddElement(ref xDoc, root, "VerticeVisuals");
            if(this.EntityVisuals !=null && this.EntityVisuals.Count>0)
            {
                foreach(EntityType entityType in this.EntityVisuals.Keys)
                {
                    XmlNode vNode = XmlDataUtil.AddElement(ref xDoc, vNodes, "VerticeVisual");
                    VerticeVisual visual = this.EntityVisuals[entityType];
                    XmlDataUtil.UpdateAttribute(ref xDoc, vNode,"EntityType",entityType.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, vNode, "SizeMeasure", visual.SizeMeasure.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, vNode, "SizeW",visual.Size.Width.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, vNode, "SizeH", visual.Size.Height.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, vNode, "Shape",visual.Shape.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, vNode, "Icon", visual.Icon);
                    XmlDataUtil.UpdateAttribute(ref xDoc, vNode, "Color", ColorUtil.ToString(visual.Color));
                    XmlDataUtil.UpdateAttribute(ref xDoc, vNode, "SelectedIcon", visual.SelectedIcon);
                    XmlDataUtil.UpdateAttribute(ref xDoc, vNode, "SelectedColor", ColorUtil.ToString(visual.SelectedColor));
                    XmlDataUtil.UpdateAttribute(ref xDoc, vNode, "ShowLabelAll", visual.ShowLabelAll.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, vNode, "LabelColor", ColorUtil.ToString(visual.LabelColor));
                    XmlDataUtil.UpdateAttribute(
                        ref xDoc, vNode, "ShowLabelWhenDegreeAbove", visual.ShowLabelsWhenDegreeAbove.ToString());
                    if(visual.ShowLabelsForNames!=null && visual.ShowLabelsForNames.Count>0)
                    {
                        XmlNode showLabelForNameNodes = XmlDataUtil.AddElement(ref xDoc, vNode, "ShowLabelForNames");
                        foreach(string name in visual.ShowLabelsForNames)
                        {
                            XmlNode showLabelForNameNode = XmlDataUtil.AddElement(
                                ref xDoc, showLabelForNameNodes, "ShowLabelForName");
                            XmlDataUtil.UpdateAttribute(ref xDoc, showLabelForNameNode, "Name", name);
                        }
                    }
                    if(visual.FlagColors !=null && visual.FlagColors.Count>0)
                    {
                        XmlNode flagNodes = XmlDataUtil.AddElement(ref xDoc, vNode, "Flags");
                        foreach(string flag in visual.FlagColors.Keys)
                        {
                            XmlNode flagNode = XmlDataUtil.AddElement(ref xDoc, flagNodes, "Flag");
                            XmlDataUtil.UpdateAttribute(ref xDoc, flagNode, "Flag",flag);
                            XmlDataUtil.UpdateAttribute(ref xDoc, flagNode, "Color",ColorUtil.ToString(visual.FlagColors[flag]));
                        }
                    }
                }
            }

            XmlNode eNodes = XmlDataUtil.AddElement(ref xDoc, root, "EdgeVisuals");
            foreach(EntityType fromEntity in this.EdgeVisuals.Keys)
            {
                Dictionary<EntityType, EdgeVisual> evs = this.EdgeVisuals[fromEntity];
                foreach(EntityType toEntity in evs.Keys)
                {
                    EdgeVisual ev = evs[toEntity];
                    XmlNode eNode = XmlDataUtil.AddElement(ref xDoc, eNodes, "EdgeVisual");
                    XmlDataUtil.UpdateAttribute(ref xDoc, eNode,"FromEntity",fromEntity.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, eNode, "ToEntity",toEntity.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, eNode, "LineStyle", ev.LineStyle.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, eNode, "Thickness", ev.Thickness.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, eNode, "ThicknessMeasure", ev.ThicknessMeasure.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, eNode, "Color", ColorUtil.ToString(ev.Color));
                    XmlDataUtil.UpdateAttribute(ref xDoc, eNode, "ShowDistance", ev.ShowDistance.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, eNode, "DistanceScale", ev.DistanceScale.ToString());
                }
            }
            xDoc.Save(filePath);
        }
    }
}
